package org.comix.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * 
 * @Creator paladin.xiehai
 * @CreateTime 2008-11-5 $Author$ ${date} $Revision$ $Date$
 */
public abstract class FileUtil {

	protected static Log logger = LogFactory.getLog(FileUtil.class);

	/**
	 * 
	 * @param fileName
	 * @return
	 */
	public static FileFilter createFileFilter(String fileName) {
		if (fileName == null || fileName.trim().equals("")) {
			throw new IllegalArgumentException("Get File Filter Error,invalid filename:" + fileName);
		}

		String matchFileName = fileName;

		matchFileName = StringUtil.replace(matchFileName, "*", ".*");
		matchFileName = StringUtil.replace(matchFileName, "+", ".+");
		matchFileName = StringUtil.replace(matchFileName, "?", ".?");

		int index = matchFileName.lastIndexOf(".");
		if (index >= 0) {
			matchFileName = matchFileName.substring(0, index) + "\\." + matchFileName.substring(index + 1);
		}

		final String temp = matchFileName;

		FileFilter fileFilter = new FileFilter() {
			public boolean accept(File pathname) {
				if (pathname.isDirectory()) {
					return true;
				}
				Pattern p = Pattern.compile(temp);

				if (p.matcher(pathname.getName()).matches()) {
					return true;
				}
				return false;
			}
		};

		return fileFilter;
	}

	public static List<String> searchFile(final String path, final String fileName) {

		if (!exists(path)) {
			return new ArrayList<String>();
		}

		String matchFileName = fileName;

		// StringBuffer buffer=new StringBuffer(fileName);

		matchFileName = StringUtil.replace(matchFileName, "*", ".*");
		matchFileName = StringUtil.replace(matchFileName, "+", ".+");
		matchFileName = StringUtil.replace(matchFileName, "?", ".?");

		int index = matchFileName.lastIndexOf(".");
		if (index >= 0) {
			matchFileName = matchFileName.substring(0, index) + "\\." + matchFileName.substring(index + 1);
		}

		final String temp = matchFileName;

		FileFilter fileFilter = new FileFilter() {
			public boolean accept(File pathname) {
				if (pathname.isDirectory()) {
					return false;
				}
				Pattern p = Pattern.compile(temp);

				if (p.matcher(pathname.getName()).matches()) {
					return true;
				}
				return false;
			}
		};

		File file = new File(path);

		File[] files = file.listFiles(fileFilter);

		List<String> list = new ArrayList<String>();

		for (int i = 0; i < files.length; i++) {
			list.add(files[i].getName());
		}

		return list;
	}

	public static void copyDirectory(String sourceDirName, String destDirName) {
		copyDirectory(new File(sourceDirName), new File(destDirName));
	}

	public static void copyDirectory(File sourceFile, File destFile) {
		if (sourceFile.exists() && sourceFile.isDirectory()) {
			if (!destFile.exists()) {
				destFile.mkdirs();
			}

			File[] fileArray = sourceFile.listFiles();

			for (int i = 0; i < fileArray.length; i++) {
				if (fileArray[i].isDirectory()) {
					copyDirectory(fileArray[i], new File(destFile.getPath() + File.separator + fileArray[i].getName()));
				} else {
					copyFile(fileArray[i], new File(destFile.getPath() + File.separator + fileArray[i].getName()));
				}
			}
		}
	}

	public static void copyFile(String source, String destination) {
		copyFile(source, destination, false);
	}

	public static void copyFile(String source, String destination, boolean lazy) {
		copyFile(source, destination, lazy);
	}

	public static void copyFile(File sourceFile, File destinationFile, boolean lazy) {
		if (!sourceFile.exists()) {
			return;
		}
		if (lazy) {
			String oldContent = null;
			try {
				oldContent = read(sourceFile);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				return;
			}
			String newContent = null;
			try {
				newContent = read(destinationFile);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
			if (oldContent == null || !oldContent.equals(newContent)) {
				copyFile(sourceFile, destinationFile, false);
			}
		} else {
			if ((destinationFile.getParentFile() != null) && (!destinationFile.getParentFile().exists())) {
				destinationFile.getParentFile().mkdirs();
			}
			try {
				FileChannel srcChannel = new FileInputStream(sourceFile).getChannel();
				FileChannel dstChannel = new FileOutputStream(destinationFile).getChannel();
				dstChannel.transferFrom(srcChannel, 0, srcChannel.size());

				srcChannel.close();
				dstChannel.close();
			} catch (IOException ioe) {
				logger.error(ioe.getMessage(), ioe);
			}
		}
	}

	public static void copyFile(File sourceFile, File destinationFile) {
		copyFile(sourceFile, destinationFile, false);
	}

	public static boolean deleteFile(String fileName) {
		return deleteFile(new File(fileName));
	}

	public static boolean deleteFile(File file) {
		if (file.exists()) {
			return file.delete();
		} else {
			return false;
		}
	}

	public static void deleteDirectory(String dirName) {
		deleteDirectory(new File(dirName));
	}

	public static void deleteDirectory(File directory) {
		if (directory.exists() && directory.isDirectory()) {
			File[] fileArray = directory.listFiles();

			for (int i = 0; i < fileArray.length; i++) {
				if (fileArray[i].isDirectory()) {
					deleteDirectory(fileArray[i]);
				} else {
					fileArray[i].delete();
				}
			}

			directory.delete();
		}
	}

	public static boolean exists(File file) {
		return file.exists();
	}

	public static boolean exists(String fileName) {
		return exists(new File(fileName));
	}

	public static byte[] getBytes(File file) throws IOException {
		if ((file == null) || !file.exists()) {
			return null;
		}

		FileInputStream in = new FileInputStream(file);

		byte[] bytes = getBytes(in, (int) file.length());

		in.close();

		return bytes;
	}

	public static byte[] getBytes(InputStream is) throws IOException {
		return getBytes(is, -1);
	}

	public static String getString(InputStream is) throws IOException {
		return getString(is, "GBK");
	}

	public static String getString(InputStream is, String encoding) throws IOException {
		byte[] bytes = getBytes(is);
		return new String(bytes, encoding);
	}

	public static byte[] getBytes(InputStream is, int bufferSize) throws IOException {
		ByteArrayOutputStream out = null;
		if (bufferSize <= 0) {
			out = new ByteArrayOutputStream();
		} else {
			out = new ByteArrayOutputStream(bufferSize);
		}
		boolean createBuffered = false;
		try {
			if (!(is instanceof BufferedInputStream)) {
				is = new BufferedInputStream(is);
				createBuffered = true;
			}
			int c = is.read();

			while (c != -1) {
				out.write(c);
				c = is.read();
			}
		} finally {
			if (createBuffered) {
				is.close();
			}
		}
		out.close();
		return out.toByteArray();
	}

	public static File makeDir(String fileName) {
		File file = new File(fileName);
		file.mkdirs();
		return file;
	}

	public static boolean move(String sourceName, String destName) {
		return move(new File(sourceName), new File(destName));
	}

	public static boolean move(File source, File destination) {
		if (!source.exists()) {
			return false;
		}

		destination.delete();

		return source.renameTo(destination);
	}

	public static String read(File file) throws IOException {
		FileInputStream fis = new FileInputStream(file);

		byte[] bytes = new byte[fis.available()];

		fis.read(bytes);

		fis.close();

		String s = new String(bytes, "UTF-8");

		return s;
	}

	public static String read(String fileName) throws IOException {
		return read(new File(fileName));
	}

	public static List<String> toList(String fileName) {
		try {
			return toList(new FileReader(fileName));
		} catch (IOException ioe) {
			return new ArrayList<String>();
		}
	}

	public static List<String> toList(Reader reader) {
		List<String> list = new ArrayList<String>();
		try {
			BufferedReader br = new BufferedReader(reader);
			String line = null;
			while ((line = br.readLine()) != null) {
				list.add(line);
			}
			br.close();
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
		return list;
	}

	public static void write(String fileName, String str) throws IOException {
		write(new File(fileName), str);
	}

	public static void write(File file, String str) throws IOException {
		write(file, str, false);
	}

	public static void write(File file, String str, boolean lazy) throws IOException {
		if (file.getParent() != null) {
			makeDir(file.getParent());
		}

		if (file.exists()) {
			String content = read(file);

			if (lazy) {
				if (content.equals(str)) {
					return;
				}
			}
		}
		BufferedWriter bw = new BufferedWriter(new FileWriter(file));
		bw.flush();
		bw.write(str);
		bw.close();
	}

	public static void write(String fileName, String str, boolean lazy) throws IOException {
		write(new File(fileName), str, lazy);
	}

	public static void write(String fileName, byte[] byteArray) throws IOException {
		write(new File(fileName), byteArray);
	}

	public static void write(File file, byte[] byteArray) throws IOException {
		if (file.getParent() != null) {
			makeDir(file.getParent());
		}

		FileOutputStream fos = new FileOutputStream(file);

		fos.write(byteArray);

		fos.close();
	}

	public static boolean makeFile(String fileName) throws IOException {
		File file = new File(fileName);
		if (file.getParent() != null) {
			makeDir(file.getParent());
		}
		return file.createNewFile();
	}

	public static void write(String fileName, List<String> ls) throws IOException {
		write(new File(fileName), ls);
	}

	public static void write(File file, List<String> ls) throws IOException {
		if (file.getParent() != null) {
			makeDir(file.getParent());
		}

		BufferedWriter bw = new BufferedWriter(new FileWriter(file));
		bw.flush();
		for (String str : ls) {
			bw.write(str);
			bw.newLine();
		}
		bw.close();
	}

	public static void append(File file, List<String> ls) throws IOException {
		if (file.getParent() != null) {
			makeDir(file.getParent());
		}
		BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));
		bw.flush();
		for (String str : ls) {
			bw.write(str);
			bw.newLine();
		}
		bw.close();
	}

	public static void append(String fileName, List<String> ls) throws IOException {
		append(new File(fileName), ls);
	}

}
